import os
import socket
import json
from utils import memory
import pathlib


class Client:
    def __init__(self, addr):
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._socket.connect(addr)

    def request(self, dic):
        self._socket.send(json.dumps(dic).encode('utf-8'))
        data = self._socket.recv(1000000)
        return json.loads(data.decode('utf-8'))

    def close(self):
        self._socket.close()


server_addr = ('127.0.0.1', 5005)


class RespondError(Exception):
    def __init__(self, res):
        Exception.__init__(self)
        self.res = res


def request(url, dic):
    client = Client(server_addr)
    res = client.request({
        'url': url,
        'token': memory.token,
        'body': dic
    })
    client.close()
    if res['code'] == 'OK':
        return res['body']
    else:
        raise RespondError(res)


def send_file(file_path, file_name, recipients, hook=None, as_image=False):
    sok = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sok.connect(server_addr)
    dic = {
        'url': '/file/send',
        'token': memory.token,
        'body': {
            'recipients': recipients,
            'file_name': file_name,
            'as_image': as_image
        }
    }
    sok.send(json.dumps(dic).encode('utf-8'))
    data = sok.recv(1000000)
    file_id = json.loads(data.decode('utf-8'))['body']['file_id']
    f = open(file_path, 'rb')
    f.seek(0, 2)
    total_size = f.tell()
    f.seek(0, 0)
    unit = 1000000
    while True:
        if hook is not None:
            hook(f.tell() / total_size)
        data = f.read(unit)
        if len(data) == 0:
            break
        sok.send(data)
    sok.close()
    f.close()
    return file_id


def recv_file(file_path, file_id, total_bytes=None, hook=None):
    sok = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sok.connect(server_addr)
    dic = {
        'url': '/file/recv',
        'token': memory.token,
        'body': {
            'file_id': file_id,
        }
    }
    os.makedirs(pathlib.Path(file_path).parent, exist_ok=True)
    f = open(file_path, 'wb')
    sok.send(json.dumps(dic).encode('utf-8'))
    while True:
        data = sok.recv(1000000)
        if len(data) == 0:
            break
        f.write(data)
        if hook is not None and total_bytes is not None:
            hook(f.tell() / total_bytes)
    f.close()
    sok.close()
